// 纯数据的项目树 Pinia Store，仅存储与操作 ProjectTreeNode JSON，不包含组件标签/编辑态
import { defineStore } from 'pinia'
import { getProject, updateProject } from '@/api/system/project'

// 预加载子节点模板 JSON（保持 eager，避免异步竞态；如需懒加载可去掉 eager）
const childrenTemplateModules: Record<string, any> = import.meta.glob('@/data/tree/*Children.json', { eager: true })

export interface ProjectTreeNode {
    key: string
    icon: string | null
    name: string
    type: string | null
    filePath: string | null
    fileId: number | null
    rename: boolean
    execute: string | null
    removal: boolean
    submenu: boolean
    children: ProjectTreeNode[]
    property: Record<string, any>
    uploadFile: boolean
    addChildren: boolean

}

function toBool(v: unknown): boolean {
  if (typeof v === 'string') {
    const s = v.trim().toLowerCase()
    return !(s === '' || ['false','0','no','off','null','undefined'].includes(s))
  }
  if (v === 0) return false
  return !!v
}

// 使用稳定的层级 path 作为 key，避免随机数导致 UI 展开状态丢失
export function normalizeNodes(arr: any[], parentKey = '', startIndex = 0): ProjectTreeNode[] {
  return arr.map((raw, idx) => {
    const seq = startIndex + idx
    const key = parentKey ? `${parentKey}-${seq}` : `${seq}`
    const children = Array.isArray(raw.children) ? normalizeNodes(raw.children, key, 0) : []
    // 每次都深拷贝 property，确保不会复用内存中的对象
    const property = raw.property ? JSON.parse(JSON.stringify(raw.property)) : {}
    return {
        key: key,
        icon: raw.icon ?? null,
        name: raw.name ?? '未命名',
        type: raw.type ?? null,
        filePath: raw.filePath ?? null,
        fileId: raw.fileId ?? null,
        rename: toBool(raw.rename),
        execute: raw.execute ?? null,
        removal: toBool(raw.removal),
        submenu: toBool(raw.submenu),
        children,
        property,
        uploadFile: toBool(raw.uploadFile),
        addChildren: toBool(raw.addChildren),

    }
  })
}

function parseAndNormalizeTree(responseData: any): ProjectTreeNode[] {
  let container: any = responseData?.dataInfo ?? responseData
  if (typeof container === 'string') {
    try { container = JSON.parse(container) } catch (e) { console.error('解析项目数据 JSON 失败', e); return [] }
  }
  let rawTreeData: any = container?.tree || container?.structure || container
  if (!Array.isArray(rawTreeData) && Array.isArray(rawTreeData?.children)) rawTreeData = rawTreeData.children
  return Array.isArray(rawTreeData) ? normalizeNodes(rawTreeData) : []
}

async function loadChildrenTemplateByType(type: string): Promise<any[]> {
  const key = `/src/data/tree/${type}Children.json`
  const mod = childrenTemplateModules[key]
  if (!mod) return []
  try {
    const data = mod.default || mod
      console.log('loading children template:', type, data)
    return Array.isArray(data) ? data : [data]
  } catch (e) {
    console.warn('加载子模板失败:', type, e)
    return []
  }
}

interface TreeState {
  trees: Record<string | number, ProjectTreeNode[]>
  loading: Record<string | number, boolean>
}

export const useTreeStore = defineStore('tree', {
  state: (): TreeState => ({
    trees: {},
    loading: {}
  }),
  actions: {
    getTree(projectId: string | number | null): ProjectTreeNode[] {
      if (projectId == null) return []
      return this.trees[toKey(projectId)] || []
    },
    isLoading(projectId: string | number | null): boolean {
      if (projectId == null) return false
      return !!this.loading[toKey(projectId)]
    },
    setTree(projectId: string | number, tree: ProjectTreeNode[]): void {
      this.trees[toKey(projectId)] = tree
    },
    setLoading(projectId: string | number, v: boolean): void {
      this.loading[toKey(projectId)] = v
    },
    async load(projectId: string | number | null): Promise<void> {
      if (projectId == null) return
      const key = toKey(projectId)
      this.setLoading(key, true)
      try {
        const res: any = await getProject(projectId)
        if (res?.code === 200) this.setTree(key, parseAndNormalizeTree(res.data))
        else this.setTree(key, [])
      } catch (e) {
        console.error('加载项目树异常', e)
        this.setTree(key, [])
      } finally {
        this.setLoading(key, false)
      }
    },
    async addChildNodes(projectId: string | number | null, node: ProjectTreeNode): Promise<ProjectTreeNode[]> {
      if (projectId == null || !node?.type) return []
      const rawChildren = await loadChildrenTemplateByType(node.type)
        console.log('loaded children template:', node.type, rawChildren)
      if (rawChildren.length === 0) return []
      const startIndex = node.children.length
      const newNodes = normalizeNodes(rawChildren, node.key, startIndex)
      node.children.push(...newNodes)
      return newNodes
    },
    renameNode(node: ProjectTreeNode, newName: string): void {
      if (node && newName.trim()) node.name = newName.trim()
    },
    /**
     * 删除指定节点（如果其 removal 标志允许）。
     * 不重新分配 key，避免整棵树的引用断裂；ElementPlus 允许 key 间存在“缺口”。
     * @returns 是否成功删除
     */
    removeNode(projectId: string | number | null, target: ProjectTreeNode | null): boolean {
      if (projectId == null || !target || !target.removal) return false
      const tree = this.getTree(projectId)
      if (!tree.length) return false
      let removed = false
      const dfs = (arr: ProjectTreeNode[]): boolean => {
        const idx = arr.findIndex(n => n === target)
        if (idx >= 0) { arr.splice(idx, 1); return true }
        for (const n of arr) { if (dfs(n.children)) return true }
        return false
      }
      removed = dfs(tree)
      return removed
    },
    async saveTree(projectId: string | number): Promise<any> {
      // 构造全量树数据并持久化；保持字符串 ID（避免大整数精度丢失）
      const id = toKey(projectId)
      const tree = this.getTree(id) || []
      let dataInfo: any
      try { dataInfo = JSON.stringify(tree) } catch { dataInfo = tree }
      const payload = { id, dataInfo }
      try {
        return await updateProject(payload)
      } catch (e) {
        console.error('保存项目树失败', e)
        throw e
      }
    },
    updateNodeProperty(projectId: string | number, nodeKey: string, property: Record<string, any>) {
      const tree = this.getTree(projectId)
      if (!tree.length) return
      const dfs = (arr: ProjectTreeNode[]) => {
        for (const node of arr) {
          if (node.key === nodeKey) {
            node.property = { ...property }
            return true
          }
          if (node.children && node.children.length) {
            if (dfs(node.children)) return true
          }
        }
        return false
      }
      dfs(tree)
    },
  }
})

export default useTreeStore

function toKey(id: string | number): string { return String(id) }
